]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
extensions-tool: Implement create command
authorFlorian Müllner <fmuellner@gnome.org>
Mon, 27 Aug 2018 01:24:10 +0000 (03:24 +0200)
committerFlorian Müllner <fmuellner@gnome.org>
Wed, 21 Aug 2019 16:28:02 +0000 (18:28 +0200)
This implements more functionality of the existing tool and, as
'reload' is an unreliable feature that doesn't work more often
than not, the last bit that we will replicate.

The command follows the original for the most part, with the most
important difference being the installed template, which doesn't
provide any sample functionality and uses modern JS syntax.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1234

src/extensions-tool/command-create.c [new file with mode: 0644]
src/extensions-tool/commands.h
src/extensions-tool/common.h
src/extensions-tool/gnome-extensions-tool.gresource.xml [new file with mode: 0644]
src/extensions-tool/main.c
src/extensions-tool/meson-src.build
src/extensions-tool/meson.build
src/extensions-tool/template/extension.js [new file with mode: 0644]
src/extensions-tool/template/stylesheet.css [new file with mode: 0644]

diff --git a/src/extensions-tool/command-create.c b/src/extensions-tool/command-create.c
new file mode 100644 (file)
index 0000000..5c43c68
--- /dev/null
@@ -0,0 +1,256 @@
+/* command-create.c
+ *
+ * Copyright 2018 Florian Müllner <fmuellner@gnome.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gio/gunixinputstream.h>
+
+#include "commands.h"
+#include "common.h"
+
+static char *
+get_shell_version (GError **error)
+{
+  g_autoptr (GDBusProxy) proxy = NULL;
+  g_autoptr (GVariant) variant = NULL;
+  g_auto (GStrv) split_version = NULL;
+
+  proxy = get_shell_proxy (error);
+  if (proxy == NULL)
+    return NULL;
+
+  variant = g_dbus_proxy_get_cached_property (proxy, "ShellVersion");
+  if (variant == NULL)
+    return NULL;
+
+  split_version = g_strsplit (g_variant_get_string (variant, NULL), ".", 3);
+  if (g_ascii_strtoll (split_version[1], NULL, 10) % 2 == 0)
+    g_clear_pointer (&split_version[2], g_free);
+
+  return g_strjoinv (".", split_version);
+}
+
+static gboolean
+create_metadata (GFile       *target_dir,
+                 const char  *uuid,
+                 const char  *name,
+                 const char  *description,
+                 GError     **error)
+{
+  g_autoptr (GFile) target = NULL;
+  g_autoptr (GString) json = NULL;
+  g_autofree char *version = NULL;
+
+  version = get_shell_version (error);
+  if (version == NULL)
+    return FALSE;
+
+  json = g_string_new ("{\n");
+
+  g_string_append_printf (json, "  \"name\": \"%s\",\n", name);
+  g_string_append_printf (json, "  \"description\": \"%s\",\n", description);
+  g_string_append_printf (json, "  \"uuid\": \"%s\",\n", uuid);
+  g_string_append_printf (json, "  \"shell-version\": [\n");
+  g_string_append_printf (json, "    \"%s\"\n", version);
+  g_string_append_printf (json, "  ]\n}\n");
+
+  target = g_file_get_child (target_dir, "metadata.json");
+  return g_file_replace_contents (target,
+                                  json->str,
+                                  json->len,
+                                  NULL,
+                                  FALSE,
+                                  0,
+                                  NULL,
+                                  NULL,
+                                  error);
+}
+
+
+#define TEMPLATE_PATH "/org/gnome/extensions-tool/template"
+static gboolean
+copy_extension_template (GFile *target_dir, GError **error)
+{
+  g_auto (GStrv) templates;
+  char **s;
+
+  templates = g_resources_enumerate_children (TEMPLATE_PATH, 0, NULL);
+  for (s = templates; *s; s++)
+    {
+      g_autoptr (GFile) target = NULL;
+      g_autoptr (GFile) source = NULL;
+      g_autofree char *uri = NULL;
+
+      uri = g_strdup_printf ("resource://%s/%s", TEMPLATE_PATH, *s);
+      source = g_file_new_for_uri (uri);
+      target = g_file_get_child (target_dir, *s);
+
+      if (!g_file_copy (source, target, G_FILE_COPY_TARGET_DEFAULT_PERMS, NULL, NULL, NULL, error))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+launch_extension_source (GFile *dir, GError **error)
+{
+  g_autoptr (GFile) main_source = NULL;
+  g_autoptr (GAppInfo) handler = NULL;
+  GList l;
+
+  main_source = g_file_get_child (dir, "extension.js");
+  handler = g_file_query_default_handler (main_source, NULL, error);
+  if (handler == NULL)
+    return FALSE;
+
+  l.data = main_source;
+  l.next = l.prev = NULL;
+
+  return g_app_info_launch (handler, &l, NULL, error);
+}
+
+static gboolean
+create_extension (const char *uuid, const char *name, const char *description)
+{
+  g_autoptr (GFile) dir = NULL;
+  g_autoptr (GError) error = NULL;
+
+  dir = g_file_new_build_filename (g_get_user_data_dir (),
+                                   "gnome-shell",
+                                   "extensions",
+                                   uuid,
+                                   NULL);
+
+  if (!g_file_make_directory_with_parents (dir, NULL, &error))
+    {
+      g_printerr ("%s\n", error->message);
+      return FALSE;
+    }
+
+  if (!create_metadata (dir, uuid, name, description, &error))
+    {
+      g_printerr ("%s\n", error->message);
+      return FALSE;
+    }
+
+  if (!copy_extension_template (dir, &error))
+    {
+      g_printerr ("%s\n", error->message);
+      return FALSE;
+    }
+
+  if (!launch_extension_source (dir, &error))
+    {
+      g_printerr ("%s\n", error->message);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static void
+prompt_metadata (char **uuid, char **name, char **description)
+{
+  g_autoptr (GInputStream) stdin = NULL;
+  g_autoptr (GDataInputStream) istream = NULL;
+
+  stdin = g_unix_input_stream_new (0, FALSE);
+  istream = g_data_input_stream_new (stdin);
+
+  if (name != NULL)
+    {
+      char *line;
+
+      g_print (
+        _("Name should be a very short (ideally descriptive) string.\n"
+          "Examples are: %s"),
+        "“Click To Focus”, “Adblock”, “Shell Window Shrinker”\n");
+      g_print ("%s: ", _("Name"));
+
+      line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
+      *name = g_strdelimit (line, "\n", '\0');
+    }
+
+  if (description != NULL)
+    {
+      char *line;
+
+      g_print (
+        _("Description is a single-sentence explanation of what your extension does.\n"
+          "Examples are: %s"),
+        "“Make windows visible on click”, “Block advertisement popups”, “Animate windows shrinking on minimize”\n");
+      g_print ("%s: ", _("Description"));
+
+      line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
+      *description = g_strdelimit (line, "\n", '\0');
+    }
+
+  if (uuid != NULL)
+    {
+      char *line;
+
+      g_print (
+        _("UUID is a globally-unique identifier for your extension.\n"
+          "This should be in the format of an email address (clicktofocus@janedoe.example.com)\n"));
+      g_print ("UUID: ");
+
+      line = g_data_input_stream_read_line_utf8 (istream, NULL, NULL, NULL);
+      *uuid = g_strdelimit (line, "\n", '\0');
+    }
+}
+
+int
+handle_create (int argc, char *argv[], gboolean do_help)
+{
+  g_autoptr (GOptionContext) context = NULL;
+  g_autoptr (GError) error = NULL;
+  g_autofree char *name = NULL;
+  g_autofree char *description = NULL;
+  g_autofree char *uuid = NULL;
+
+  g_set_prgname ("gnome-extensions create");
+
+  context = g_option_context_new (NULL);
+  g_option_context_set_help_enabled (context, FALSE);
+  g_option_context_set_summary (context, _("Create a new extension"));
+
+  if (do_help)
+    {
+      show_help (context, NULL);
+      return 0;
+    }
+
+  if (!g_option_context_parse (context, &argc, &argv, &error))
+    {
+      show_help (context, error->message);
+      return 1;
+    }
+
+  if (argc > 1)
+    {
+      show_help (context, _("Unknown arguments"));
+      return 1;
+    }
+
+  prompt_metadata (&uuid, &name, &description);
+
+  return create_extension (uuid, name, description) ? 0 : 2;
+}
index c0b0ba18cce4ab7c355b926ee4ee57e582ab06c3..f2b4c712f0770f76b4631179f0622ddfac6a23df 100644 (file)
@@ -26,5 +26,6 @@ G_BEGIN_DECLS
 
 int handle_enable     (int argc, char *argv[], gboolean do_help);
 int handle_disable    (int argc, char *argv[], gboolean do_help);
+int handle_create     (int argc, char *argv[], gboolean do_help);
 
 G_END_DECLS
index c3a243c929c91a8806c1ad5f92548de563afa69c..1c8b4cdd244d190744f9a6c762f19f3d36f3f42c 100644 (file)
 
 #pragma once
 
-#include <glib.h>
+#include <gio/gio.h>
 
 G_BEGIN_DECLS
 
 void show_help (GOptionContext *context,
                 const char     *message);
 
+GDBusProxy *get_shell_proxy (GError **error);
 GSettings  *get_shell_settings (void);
 
 G_END_DECLS
diff --git a/src/extensions-tool/gnome-extensions-tool.gresource.xml b/src/extensions-tool/gnome-extensions-tool.gresource.xml
new file mode 100644 (file)
index 0000000..2aad7b1
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/org/gnome/extensions-tool">
+    <file>template/extension.js</file>
+    <file>template/stylesheet.css</file>
+  </gresource>
+</gresources>
index 81c72a3ac02aedbe528c8e85a1c81dcbae6512f5..19c331112be4221e184fa4ebbe0e140525439a16 100644 (file)
@@ -38,6 +38,19 @@ show_help (GOptionContext *context, const char *message)
   g_printerr ("%s", help);
 }
 
+GDBusProxy *
+get_shell_proxy (GError **error)
+{
+  return g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+                                        G_DBUS_PROXY_FLAGS_NONE,
+                                        NULL,
+                                        "org.gnome.Shell",
+                                        "/org/gnome/Shell",
+                                        "org.gnome.Shell.Extensions",
+                                        NULL,
+                                        error);
+}
+
 GSettings *
 get_shell_settings (void)
 {
@@ -87,6 +100,7 @@ usage (void)
   g_printerr ("  version   %s\n", _("Print version"));
   g_printerr ("  enable    %s\n", _("Enable extension"));
   g_printerr ("  disable   %s\n", _("Disable extension"));
+  g_printerr ("  create    %s\n", _("Create extension"));
   g_printerr ("\n");
   g_printerr (_("Use %s to get detailed help.\n"), "“gnome-extensions help COMMAND”");
 }
@@ -144,6 +158,8 @@ main (int argc, char *argv[])
     return handle_enable (argc, argv, do_help);
   else if (g_str_equal (command, "disable"))
     return handle_disable (argc, argv, do_help);
+  else if (g_str_equal (command, "create"))
+    return handle_create (argc, argv, do_help);
   else
     usage ();
 
index fb3ab04d170b8c350609e7b6ceba64336f5a74c9..d11a75ba2dcbc5293b0c03f1e01621405490ecde 100644 (file)
@@ -1,12 +1,19 @@
 sources = [
   'commands.h',
+  'command-create.c',
   'command-disable.c',
   'command-enable.c',
   'common.h',
   'main.c'
 ]
+
+resources = gnome.compile_resources('resources',
+  'gnome-extensions-tool.gresource.xml',
+  source_dir: '.'
+)
+
 executable('gnome-extensions',
-  sources,
-  dependencies: gio_dep,
+  sources, resources,
+  dependencies: [gio_dep, gio_unix_dep],
   install: true
 )
index 2e03539c4b4b59a5311cdd84bf174c55e509a7af..35d5245b5e68a0550bc3176f64221ba234716357 100644 (file)
@@ -9,13 +9,19 @@ configure_file(
 )
 
 sources = [
+  'command-create.c',
   'command-disable.c',
   'command-enable.c',
   'main.c'
 ]
 
+resources = gnome.compile_resources('resources',
+  'gnome-extensions-tool.gresource.xml',
+  source_dir: '.'
+)
+
 executable('gnome-extensions',
-  sources,
-  dependencies: gio_dep,
+  sources, resources,
+  dependencies: [gio_dep, gio_unix_dep],
   install: true
 )
diff --git a/src/extensions-tool/template/extension.js b/src/extensions-tool/template/extension.js
new file mode 100644 (file)
index 0000000..64857af
--- /dev/null
@@ -0,0 +1,34 @@
+/* extension.js
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+/* exported init */
+
+class Extension {
+    constructor() {
+    }
+
+    enable() {
+    }
+
+    disable() {
+    }
+}
+
+function init() {
+    return new Extension();
+}
diff --git a/src/extensions-tool/template/stylesheet.css b/src/extensions-tool/template/stylesheet.css
new file mode 100644 (file)
index 0000000..37b93f2
--- /dev/null
@@ -0,0 +1 @@
+/* Add your custom extension styling here */